package test

import (
	"aigen-todo/internal/repository"
	"aigen-todo/internal/service"
	"testing"

	"github.com/DATA-DOG/go-sqlmock"
	"github.com/stretchr/testify/assert"
	"gorm.io/driver/postgres"
	"gorm.io/gorm"
)

// TestUserService_Register 测试用户注册功能
func TestUserService_Register(t *testing.T) {
	// 创建sqlmock数据库连接
	db, mock, err := sqlmock.New()
	assert.NoError(t, err)
	defer db.Close()

	// 创建GORM实例
	gormDB, err := gorm.Open(postgres.New(postgres.Config{
		Conn: db,
	}), &gorm.Config{})
	assert.NoError(t, err)

	// 创建用户仓库和用户服务
	userRepo := repository.NewUserRepository(gormDB)
	userService := service.NewUserService(userRepo)

	// 测试用例1: 成功注册用户
	t.Run("SuccessfulRegistration", func(t *testing.T) {
		// 设置mock期望
		mock.ExpectBegin()
		mock.ExpectQuery(`INSERT INTO "users"`).
			WithArgs(sqlmock.AnyArg(), "testuser", "test@example.com", sqlmock.AnyArg(), sqlmock.AnyArg(), sqlmock.AnyArg()).
			WillReturnRows(sqlmock.NewRows([]string{"id"}).AddRow(1))
		mock.ExpectCommit()

		// 执行测试
		user, err := userService.Register("testuser", "test@example.com", "password123")

		// 验证结果
		assert.NoError(t, err)
		assert.NotNil(t, user)
		assert.Equal(t, uint64(1), user.ID)
		assert.Equal(t, "testuser", user.Username)
		assert.Equal(t, "test@example.com", user.Email)
	})

	// 测试用例2: 用户名已存在
	t.Run("UserAlreadyExists", func(t *testing.T) {
		// 设置mock期望
		mock.ExpectBegin()
		mock.ExpectQuery(`INSERT INTO "users"`).
			WithArgs(sqlmock.AnyArg(), "existinguser", "existing@example.com", sqlmock.AnyArg(), sqlmock.AnyArg(), sqlmock.AnyArg()).
			WillReturnError(&pqError{Code: "23505"}) // 唯一约束违反错误
		mock.ExpectRollback()

		// 执行测试
		user, err := userService.Register("existinguser", "existing@example.com", "password123")

		// 验证结果
		assert.Error(t, err)
		assert.Nil(t, user)
		assert.Equal(t, service.ErrUserAlreadyExists, err)
	})

	// 确保所有mock期望都被满足
	assert.NoError(t, mock.ExpectationsWereMet())
}

// TestUserService_Login 测试用户登录功能
func TestUserService_Login(t *testing.T) {
	// 创建sqlmock数据库连接
	db, mock, err := sqlmock.New()
	assert.NoError(t, err)
	defer db.Close()

	// 创建GORM实例
	gormDB, err := gorm.Open(postgres.New(postgres.Config{
		Conn: db,
	}), &gorm.Config{})
	assert.NoError(t, err)

	// 创建用户仓库和用户服务
	userRepo := repository.NewUserRepository(gormDB)
	userService := service.NewUserService(userRepo)

	// 测试用例1: 成功登录
	t.Run("SuccessfulLogin", func(t *testing.T) {
		// 设置mock期望
		rows := sqlmock.NewRows([]string{"id", "username", "email", "password"}).
			AddRow(1, "testuser", "test@example.com", "$2a$10$N.zmdr9k7uOCQb0bta/OauRxaOKSr.QhqyD2R5FKvMQjmHoLkm5Sy") // bcrypt hash of "password123"

		mock.ExpectQuery(`SELECT \* FROM "users" WHERE username = \$1 AND "users"\."deleted_at" IS NULL ORDER BY "users"\."id" LIMIT 1`).
			WithArgs("testuser").
			WillReturnRows(rows)

		// 执行测试
		user, err := userService.Login("testuser", "password123")

		// 验证结果
		assert.NoError(t, err)
		assert.NotNil(t, user)
		assert.Equal(t, uint64(1), user.ID)
		assert.Equal(t, "testuser", user.Username)
	})

	// 测试用例2: 用户不存在
	t.Run("UserNotFound", func(t *testing.T) {
		// 设置mock期望
		mock.ExpectQuery(`SELECT \* FROM "users" WHERE username = \$1 AND "users"\."deleted_at" IS NULL ORDER BY "users"\."id" LIMIT 1`).
			WithArgs("nonexistent").
			WillReturnRows(sqlmock.NewRows([]string{}))

		// 执行测试
		user, err := userService.Login("nonexistent", "password123")

		// 验证结果
		assert.Error(t, err)
		assert.Nil(t, user)
		assert.Equal(t, service.ErrInvalidCredentials, err)
	})

	// 测试用例3: 密码错误
	t.Run("InvalidPassword", func(t *testing.T) {
		// 设置mock期望
		rows := sqlmock.NewRows([]string{"id", "username", "email", "password"}).
			AddRow(1, "testuser", "test@example.com", "$2a$10$N.zmdr9k7uOCQb0bta/OauRxaOKSr.QhqyD2R5FKvMQjmHoLkm5Sy") // bcrypt hash of "password123"

		mock.ExpectQuery(`SELECT \* FROM "users" WHERE username = \$1 AND "users"\."deleted_at" IS NULL ORDER BY "users"\."id" LIMIT 1`).
			WithArgs("testuser").
			WillReturnRows(rows)

		// 执行测试
		user, err := userService.Login("testuser", "wrongpassword")

		// 验证结果
		assert.Error(t, err)
		assert.Nil(t, user)
		assert.Equal(t, service.ErrInvalidCredentials, err)
	})

	// 确保所有mock期望都被满足
	assert.NoError(t, mock.ExpectationsWereMet())
}

// pqError 模拟PostgreSQL错误
type pqError struct {
	Code string
}

func (e *pqError) Error() string {
	return "pq error"
}

func (e *pqError) SQLState() string {
	return e.Code
}
